#ifndef HASH_H
#define HASH_H
#include <stdbool.h>
#include <stdlib.h>

/* ******************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS
 * *****************************************************************/

typedef struct hash_elemento hash_elemento_t;

typedef struct hash hash_t;

typedef struct hash_iter hash_iter_t;

typedef void (*hash_destruir_dato_t)(void *);

/* ******************************************************************
 *                    PRIMITIVAS DEL HASH
 * *****************************************************************/

// Crea un hash.
// Post: devuelve un nuevo hash vacio.
hash_t *hash_crear(hash_destruir_dato_t destruir_dato);

// Guarda un elemento en el hash.
// Pre: el hash fue creado.
// Post: Guarda en el hash el elemento con la clave y dato pasados por parametro. La cantidad de elementos
// del hash aumenta en uno. Devuelve true si la operación se realizo con éxito, false en caso contrario.
bool hash_guardar(hash_t *hash, const char *clave, void *dato);

// Borra del hash el elemento asociado a la clave y lo devuelve.
// Pre: el hash fue creado.
// Post: Se elimino del hash el elemento asociado a la clave. Se devolvio el elemento borrado o NULL
// si el hash estaba vacio. La cantidad de elementos decrecio en uno.
void *hash_borrar(hash_t *hash, const char *clave);

// Obtiene el valor del elemento asociado a la clave.
// Pre: el hash fue creado.
// Post: Se devolvió el elemento asociado a la clave o NULL si el hash estaba vacío.
void *hash_obtener(const hash_t *hash, const char *clave);

// Indica si un elemento pertenece o no al hash.
// Pre: el hash fue creado.
// Post: devuelve true si el elemento pertenece al hash, false en caso contrario.
bool hash_pertenece(const hash_t *hash, const char *clave);

// Devuelve la cantidad de elementos almacenados en el hash.
// Pre: el hash fue creado.
int hash_cantidad(const hash_t *hash);

// Destruye el hash. Si se recibe la funcion destruir_dato por parametro en hash_crear
// se le aplicara a cada uno de los elementos del hash.
// Pre: el hash fue creado. destruir_dato es una función capaz de destruir
// los datos del hash, o NULL en caso de que no se la utilice.
// Post: se eliminaron todos los elementos del hash. Si es el caso, se le aplico la función
// destruir dato a cada elemento del hash.
void hash_destruir(hash_t *hash);

/* ******************************************************************
 *                    PRIMITIVAS DEL ITERADOR
 * *****************************************************************/

// Crea un iterador para el hash.
// Pre: el hash fue creado.
// Post: devuelve un iterador asociado al hash.
hash_iter_t *hash_iter_crear(const hash_t *hash);

// Avanza un elemento en el hash.
// Pre: el iterador fue creado.
// Post: el iterador hace referencia al siguiente elemento del hash. Devuelve true
// si se pudo avanzar, false en caso contrario.
bool hash_iter_avanzar(hash_iter_t *iter);

// Devuelve la clave a la cual el iterador apunta.
// Pre: el iterador fue creado.
// Post: Devuelve la clave actual del iterador o NULL si el hash esta vacio.
const char *hash_iter_ver_actual(const hash_iter_t *iter);

// Indica si el iterador esta al final del hash.
// Pre: el iterador fue creado.
// Post: Devuelve true si el hash esta al final del hash, false en caso contrario.
bool hash_iter_al_final(const hash_iter_t *iter);

// Destruye el iterador.
// Pre: el iterador fue creado.
// Post: se destruye el iterador.
void hash_iter_destruir(hash_iter_t* iter);

#endif	//HASH_H
